/*!
 * \file ems_comm.h
 *
 * \brief TIBCO EMS模块共通文件
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.
 *
 * \version 1.0
 * \author songbb
 * \date 2016/10/24
 *
 */

#ifndef __EMS_COMM_H_
#define __EMS_COMM_H_

#include <sys/time.h>

#include "frlog.h"
#include "frreport_comm.h"

#include "ems_core.h"

#define APM_EMS_DBG 0              //!< TE的Debug开关
#define APM_EMS_ENABLE_FRLOG 0     //!< FRLOG开关

#define APM_EMS_FLAG_UNSET -1      //!< 标识符变量的初始化值

#define APM_EMS_HASH_SIZE 100      //!< TIBCO EMS模块哈希桶的最大尺寸

#define EMS_PKT_TYPE2STR(x) ((x==EMS_PKT_TYPE_NONE)?"NONE": \
                               ((x==EMS_PKT_TYPE_BYTES_MSG)?"_BYTES_MSG_": \
                               ((x==EMS_PKT_TYPE_STREAM_MSG)?"_STREAM_MSG_": \
                               ((x==EMS_PKT_TYPE_TEXT_MSG)?"_TEXT_MSG_": \
                               ((x==EMS_PKT_TYPE_OBJECT_MSG)?"_OBJECT_MSG_": \
                               ((x==EMS_PKT_TYPE_MAP_MSG)?"_MAP_MSG_": \
                               ((x==EMS_PKT_TYPE_DATA_MSG)?"_DATA_MSG_": \
                               ((x==EMS_PKT_TYPE_CONFIRM)?"_CONFIRM_": \
                               ((x==EMS_PKT_TYPE_RESPONSE_OK)?"_RESPONSE_OK_": \
                               ((x==EMS_PKT_TYPE_RESPONSE_ERR)?"_RESPONSE_ERR_": \
                               ((x==EMS_PKT_TYPE_INIT_CONNECTION)?"_INIT_CONNECTION_": \
                               ((x==EMS_PKT_TYPE_DESTROY_CONNECTION)?"_DESTROY_CONNECTION_": \
                               ((x==EMS_PKT_TYPE_START_CONNECTION)?"_START_CONNECTION_": \
                               ((x==EMS_PKT_TYPE_STOP_CONNECTION)?"_STOP_CONNECTION_": \
                               ((x==EMS_PKT_TYPE_INIT_SESSION)?"_INIT_SESSION_": \
                               ((x==EMS_PKT_TYPE_DESTROY_SESSION)?"_DESTROY_SESSION_": \
                               ((x==EMS_PKT_TYPE_RECOVER_SESSION)?"_RECOVER_SESSION_": \
                               ((x==EMS_PKT_TYPE_COMMIT_SESSION)?"_COMMIT_SESSION_": \
                               ((x==EMS_PKT_TYPE_ROLLBACK_SESSION)?"_ROLLBACK_SESSION_": \
                               ((x==EMS_PKT_TYPE_INIT_CONSUMER)?"_INIT_CONSUMER_": \
                               ((x==EMS_PKT_TYPE_DESTROY_CONSUMER)?"_DESTROY_CONSUMER_": \
                               ((x==EMS_PKT_TYPE_INIT_PRODUCER)?"_INIT_PRODUCER_": \
                               ((x==EMS_PKT_TYPE_DESTROY_PRODUCER)?"_DESTROY_PRODUCER_": \
                               ((x==EMS_PKT_TYPE_UNSUBSCRIBE_CONSUMER)?"_UNSUBSCRIBE_CONSUMER_": \
                               ((x==EMS_PKT_TYPE_START_CONSUMER)?"_START_CONSUMER_": \
                               ((x==EMS_PKT_TYPE_STOP_CONSUMER)?"_STOP_CONSUMER_": \
                               ((x==EMS_PKT_TYPE_RID_FLOW_REQUEST)?"_RID_FLOW_REQUEST_": \
                               ((x==EMS_PKT_TYPE_FLOW_REQUEST)?"_FLOW_REQUEST_": \
                               ((x==EMS_PKT_TYPE_FLOW_RESPONSE)?"_FLOW_RESPONSE_": \
                               ((x==EMS_PKT_TYPE_INIT_BROWSER)?"_INIT_BROWSER_": \
                               ((x==EMS_PKT_TYPE_DESTROY_BROWSER)?"_DESTROY_BROWSER_": \
                               ((x==EMS_PKT_TYPE_BROWSER_RETRIEVE)?"_BROWSER_RETRIEVE_": \
                               ((x==EMS_PKT_TYPE_TMP_DEST_DESTROY)?"_TMP_DEST_DESTROY_": \
                               ((x==EMS_PKT_TYPE_PURGE_RECORD)?"_PURGE_RECORD_": \
                               ((x==EMS_PKT_TYPE_SET_CLIENTID)?"_SET_CLIENTID_": \
                               ((x==EMS_PKT_TYPE_TMP_DEST_CREATE)?"_TMP_DEST_CREATE_": \
                               ((x==EMS_PKT_TYPE_SSL_RENEGOTIATE_PREREQUEST)?"_SSL_RENEGOTIATE_PREREQUEST_": \
                               ((x==EMS_PKT_TYPE_SSL_RENEGOTIATE_REQUEST)?"_SSL_RENEGOTIATE_REQUEST_": \
                               ((x==EMS_PKT_TYPE_SSL_RENEGOTIATE_PROCEED)?"_SSL_RENEGOTIATE_PROCEED_": \
                               ((x==EMS_PKT_TYPE_SSL_RESET_TO_TCP)?"_SSL_RESET_TO_TCP_": \
                               ((x==EMS_PKT_TYPE_FT_INFO)?"_FT_INFO_": \
                               ((x==EMS_PKT_TYPE_XA_RECOVER)?"_XA_RECOVER_": \
                               ((x==EMS_PKT_TYPE_XA_START)?"_XA_START_": \
                               ((x==EMS_PKT_TYPE_XA_END)?"_XA_END_": \
                               ((x==EMS_PKT_TYPE_XA_PREPARE)?"_XA_PREPARE_": \
                               ((x==EMS_PKT_TYPE_XA_COMMIT)?"_XA_COMMIT_": \
                               ((x==EMS_PKT_TYPE_XA_ROLLBACK)?"_XA_ROLLBACK_": \
                               ((x==EMS_PKT_TYPE_ASYNC_CLIENT_CMD)?"_ASYNC_CLIENT_CMD_": \
                               ((x==EMS_PKT_TYPE_RECOVER_MSG)?"_RECOVER_MSG_": \
                               ((x==EMS_PKT_TYPE_RECOVER_CONSUMER_MSG)?"_RECOVER_CONSUMER_MSG_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_INIT_CONNECTION)?"_MDAEMON_INIT_CONNECTION_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_CONNECTION_DESTROY)?"_MDAEMON_CONNECTION_DESTROY_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_CONNECTION_START)?"_MDAEMON_CONNECTION_START_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_CONNECTION_STOP)?"_MDAEMON_CONNECTION_STOP_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_CONSUMER_START)?"_MDAEMON_CONSUMER_START_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_CONSUMER_STOP)?"_MDAEMON_CONSUMER_STOP_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_CONSUMER_INIT)?"_MDAEMON_CONSUMER_INIT_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_CONSUMER_DESTROY)?"_MDAEMON_CONSUMER_DESTROY_": \
                               ((x==EMS_PKT_TYPE_MDAEMON_STATS)?"_MDAEMON_STATS_": \
                               ((x==EMS_PKT_TYPE_ASYNC_MDAEMON_CMD)?"_ASYNC_MDAEMON_CMD_": \
                               ((x==EMS_PKT_TYPE_MULTICAST_CLIENT_NOTIFY)?"_MULTICAST_CLIENT_NOTIFY_": \
                               ((x==EMS_PKT_TYPE_MULTICAST_CONFIG)?"_MULTICAST_CONFIG_": \
                               ((x==EMS_PKT_TYPE_MULTICAST_CONFIG_REQUEST)?"_MULTICAST_CONFIG_REQUEST_": \
                               ((x==EMS_PKT_TYPE_MULTICAST_CLIENT_STATUS)?"_MULTICAST_CLIENT_STATUS_": \
                               ((x==EMS_PKT_TYPE_MULTICAST_DAEMON_STATUS)?"_MULTICAST_DAEMON_STATUS_": \
                               ((x==EMS_PKT_TYPE_LAST_TYPE)?"_LAST_TYPE_":"UNKNOWN"))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))  //!< 数据包类型转字符串

#define EMS_OBJECT_TYPE2STR(x) ((x==EMS_OBJECT_TYPE_NULL)?"_NULL_": \
                               ((x==EMS_OBJECT_TYPE_BOOL)?"_BOOL_": \
                               ((x==EMS_OBJECT_TYPE_BYTE)?"_BYTE_": \
                               ((x==EMS_OBJECT_TYPE_WCHAR)?"_WCHAR_": \
                               ((x==EMS_OBJECT_TYPE_SHORT)?"_SHORT_": \
                               ((x==EMS_OBJECT_TYPE_INT)?"_INT_": \
                               ((x==EMS_OBJECT_TYPE_LONG)?"_LONG_": \
                               ((x==EMS_OBJECT_TYPE_FLOAT)?"_FLOAT_": \
                               ((x==EMS_OBJECT_TYPE_DOUBLE)?"_DOUBLE_": \
                               ((x==EMS_OBJECT_TYPE_UTF8)?"_UTF8_": \
                               ((x==EMS_OBJECT_TYPE_BYTES)?"_BYTES_": \
                               ((x==EMS_OBJECT_TYPE_SUBMAP)?"_SUBMAP_": \
                               ((x==EMS_OBJECT_TYPE_SHORTA_ARRAY)?"_SHORT_ARRAY_": \
                               ((x==EMS_OBJECT_TYPE_INT_ARRAY)?"_INT_ARRAY_": \
                               ((x==EMS_OBJECT_TYPE_LONG_ARRAY)?"_LONG_ARRAY_": \
                               ((x==EMS_OBJECT_TYPE_FLOAT_ARRAY)?"_FLOAT_ARRAY_": \
                               ((x==EMS_OBJECT_TYPE_DOUBLE_ARRAY)?"_DOUBLE_ARRAY_": \
                               ((x==EMS_OBJECT_TYPE_VARLONG)?"_VARLONG_": \
                               ((x==EMS_OBJECT_TYPE_SUBSTREAM)?"_SUBSTREAM_":"UNKNOWN")))))))))))))))))))  //!< OBJECT类型转字符串


#define KRED        "\x1B[0;31m"    //!< ANSI红色
#define KSALMON     "\x1B[1;31m"    //!< ANSI鲑红色
#define KGREEN      "\x1B[0;32m"    //!< ANSI绿色
#define KLIMEGREEN  "\x1B[1;32m"    //!< ANSI青柠色
#define KYELLOW     "\x1B[0;33m"    //!< ANSI黄色
#define KORANGE     "\x1B[0;34m"    //!< ANSI橘黄色
#define KBLUE       "\x1B[1;34m"    //!< ANSI蓝色
#define KMAGENTA    "\x1B[0;35m"    //!< ANSI洋红色
#define KPINK       "\x1B[1;35m"    //!< ANSI粉色
#define KCYAN       "\x1B[0;36m"    //!< ANSI青色
#define RESET       "\x1B[0m"       //!< ANSI颜色重置

#if APM_EMS_DBG
    #define EMS_PRINT(...) printf(__VA_ARGS__)                         //!< 普通的打印
    #define EMS_PRINT_DETAIL(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(__VA_ARGS__))                            //!< 打印Detail
    #define EMS_PRINT_DBG(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KGREEN),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))                                  //!< 打印debug
    #define EMS_PRINT_FATAL(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KORANGE),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))                                  //!< 打印fatal
    #define EMS_PRINT_EMERG(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KRED),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))                                  //!< 打印emergent
    #define EMS_PRINT_ALERT(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KSALMON),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))                                  //!< 打印alert
    #define EMS_PRINT_CRIT(...) (printf("[%s, Line:%u, %s()]",\
                            __FILE__,__LINE__,__func__),\
                            printf(KMAGENTA),\
                            printf(" "__VA_ARGS__),\
                            printf(RESET))                              //!< 打印critical
    #define EMS_PRINT_ERR(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KPINK),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))                                  //!< 打印error
    #define EMS_PRINT_WARN(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KYELLOW),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))                                  //!< 打印warning
    #define EMS_PRINT_NOTICE(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KLIMEGREEN),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))                                  //!< 打印notice
    #define EMS_PRINT_INFO(...) (printf("[%s, Line:%u, %s()]",\
                            __FILE__,__LINE__,__func__),\
                            printf(KBLUE),\
                            printf(" "__VA_ARGS__),\
                            printf(RESET))                              //!< 打印info
    #define PRINT_HEX_STRING(a,b,c) (printf("[%s, Line:%u, %s()] ",\
                            __FILE__,__LINE__,__func__),\
                            printf(KCYAN),\
                            printf(a":["),ems_print_hex_string(b,c),printf("]\n"),\
                            printf(RESET))                              //!< 打印十六进制字符串
    #define EMS_PRINT_PACKET_SPECIFIED(tag, packet, offset, len) (printf("[%s, Line:%u, %s()] ",\
                            __FILE__,__LINE__,__func__),\
                            printf(KORANGE),\
                            printf(tag":["),ems_print_packet_specified(packet,offset,len),printf("]\n"),\
                            printf(RESET))                              //!< 以十六进制形式打印数据包的指定位置开始的数据
    #define EMS_PRINT_PACKET_CURRENT(a,b) (printf("[%s, Line:%u, %s()] ",\
                            __FILE__,__LINE__,__func__),\
                            printf(KCYAN),\
                            printf(a":["),ems_print_packet_current(b),printf("]\n"),\
                            printf(RESET))                              //!< 以十六进制打印数据包当前位置开始的数据
    #define EMS_PRINT_PACKET(a,b) (printf("[%s, Line:%u, %s()] ",\
                            __FILE__,__LINE__,__func__),\
                            printf(KCYAN),\
                            printf(a":["),ems_print_packet(b),printf("]\n"),\
                            printf(RESET))                              //!< 以十六禁止打印整个数据包
    #define EMS_PRINT_TIMEVAL(a,b) (printf("[%s, Line:%u, %s()]",\
                            __FILE__,__LINE__,__func__),\
                            printf(KGREEN),\
                            printf(" %s", a), \
                             ems_print_timeval(b),\
                             printf(RESET))                             //!< 打印timeval
#else
    #define EMS_PRINT(...)
    #define EMS_PRINT_DETAIL(...)
    #define EMS_PRINT_DBG(...)
    #define EMS_PRINT_FATAL(...)
    #define EMS_PRINT_EMERG(...)
    #define EMS_PRINT_ALERT(...)
    #define EMS_PRINT_CRIT(...)
    #define EMS_PRINT_ERR(...)
    #define EMS_PRINT_WARN(...)
    #define EMS_PRINT_NOTICE(...)
    #define EMS_PRINT_INFO(...)
    #define PRINT_HEX_STRING(a,b,c)
    #define EMS_PRINT_PACKET_SPECIFIED(tag, packet, offset, len)
    #define EMS_PRINT_PACKET_CURRENT(a,b)
    #define EMS_PRINT_PACKET(a,b)
    #define EMS_PRINT_TIMEVAL(a,b)
#endif

#if APM_EMS_ENABLE_FRLOG
    #define EMS_FRLOG_ERROR(...) FRLOG_ERROR_DETAIL(...)               //!< 打印Log日志
#else
#define EMS_FRLOG_ERROR(...)
#endif

#define EMS_MALLOCK_ERR EMS_PRINT_EMERG("can not malloc memory\n"); \
                          FRLOG_ERROR_DETAIL("can not malloc memory");  //!< malloc执行出错记录

/*!
 * 释放内存
 *
 * \param pp_buffer  (内存两重指针)
 *
 */
void ems_free(void **pp_buffer);

/*!
 * 打印时间戳
 *
 * \param st_timestamp  (时间戳)
 *
 */
void ems_print_timeval(struct timeval st_timestamp);

/*!
 * 格式化成十六进制字符串
 *
 * \param p_inbuff          (输入的buff)
 * \param i_inbuff_len      (输入的buff长度)
 * \param p_outbuff         (输出的buff)
 * \param i_outbuff_len     (输出的buff长度)
 *
 */
void ems_bin_to_hex_string(char *p_inbuff
                        , int i_inbuff_len
                        , char *p_outbuff
                        , int i_outbuff_len);

int ems_hex_string_to_bin(const char *p_hex_string
                        , char **pp_out_buff
                        , int *p_out_buff_size);

/*!
 * 按一个字节打印十六进行字符串
 *
 * \param p_buff    (输入的字符串)
 * \param i_len     (输入的字符串长度)
 *
 */
void ems_print_hex_string(char *p_buff
                        , int i_len);

/*!
 * 打印指定位置的包内容
 *
 * \param p_st_ems_packet      (TIBCO EMS数据包)
 * \param i_pos                 (开始位置)
 * \param i_len                 (长度)
 *
 */
void ems_print_packet_specified(L7_ems_packet *p_st_ems_packet
                                , int i_pos
                                , int i_len);

/*!
 * 打印当前位置开始的包内容
 *
 * \param p_st_ems_packet      (TIBCO EMS数据包)
 *
 */
void ems_print_packet_current(L7_ems_packet *p_st_ems_packet);

/*!
 * 打印整个包内容
 *
 * \param p_st_ems_packet      (TIBCO EMS数据包)
 *
 */
void ems_print_packet(L7_ems_packet *p_st_ems_packet);

/*!
 * 判断是否处于分片包状态
 *
 * \param p_st_ems_packet      (TIBCO EMS数据包)
 *
 * \return 0  失败\n
 *         1  成功
 *
 */
int ems_packet_is_in_fragment(L7_ems_packet *p_st_ems_packet);

/*!
 * 上报请求信息
 *
 * \param p_st_conn         (ct信息)
 * \param p_st_ems_packet    (TIBCO EMS数据包)
 * \param p_st_body         (数据上报体内容)
 * \param p_st_hash_report  (数据上报用)
 *
 * \return 0  失败\n
 *         1  成功
 *
 */
int ems_report_msg_data_req(Conntrack *p_st_conn
                        , L7_ems_packet *p_st_ems_packet
                        , Frreport_body_data *p_st_body
                        , Frhash_header *p_st_hash_report);

/*!
 * 上报响应信息
 *
 * \param p_st_conn         (ct信息)
 * \param p_st_ems_packet    (TIBCO EMS数据包)
 * \param p_st_body         (数据上报体内容)
 * \param p_st_hash_report  (数据上报用)
 *
 * \return 0  失败\n
 *         1  成功
 *
 */
int ems_report_msg_data_resp(Conntrack *p_st_conn
                            , L7_ems_packet *p_st_ems_packet
                            , Frreport_body_data *p_st_body
                            , Frhash_header *p_st_hash_report);

/*!
 * 上报NOTIFY信息
 *
 * \param p_st_conn         (ct信息)
 * \param p_st_ems_packet   (TIBCO EMS数据包)
 * \param p_st_body         (数据上报体内容)
 * \param p_st_hash_report  (数据上报用)
 *
 * \return 0  失败\n
 *         1  成功
 *
 */
int ems_report_msg_data_notify(Conntrack *p_st_conn
                            , L7_ems_packet *p_st_ems_packet
                            , Frreport_body_data *p_st_body
                            , Frhash_header *p_st_hash_report);

#endif
